<?php

class DbCommand extends CDbCommand
{
	private $_fetchMode = array(PDO::FETCH_ASSOC);
    private $_paramLog=array();

	public function __construct(DbConnection $connection, $query=null)
	{
		parent::__construct($connection, $query);
	}

	public function setFetchMode($mode)
	{
		$params=func_get_args();
		$this->_fetchMode = $params;
		return $this;
	}

	public function query($params=array())
	{
		return $this->queryInternal('',0,$params);
	}

	public function queryAll($fetchAssociative=true,$params=array())
	{
		return $this->queryInternal('fetchAll',$fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params);
	}

	public function queryRow($fetchAssociative=true,$params=array())
	{
		return $this->queryInternal('fetch',$fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params);
	}

	public function queryScalar($params=array())
	{
		$result=$this->queryInternal('fetchColumn',0,$params);
		if(is_resource($result) && get_resource_type($result)==='stream')
			return stream_get_contents($result);
		else
			return $result;
	}

	public function queryColumn($params=array())
	{
		return $this->queryInternal('fetchAll',PDO::FETCH_COLUMN,$params);
	}

	private function queryInternal($method,$mode,$params=array())
	{
		$params=array_merge($this->params,$params);

		if($this->getConnection()->enableParamLogging && ($pars=array_merge($this->_paramLog,$params))!==array())
		{
			$p=array();
			foreach($pars as $name=>$value)
				$p[$name]=$name.'='.$value;
			$par='. Bound with '.implode(', ',$p);
		}
		else
			$par='';

		Yii::trace('Querying SQL: '.$this->getText().$par,'system.db.CDbCommand');

		if($this->getConnection()->queryCachingCount>0 && $method!==''
				&& $this->getConnection()->queryCachingDuration>0
				&& $this->getConnection()->queryCacheID!==false
				&& ($cache=Yii::app()->getComponent($this->getConnection()->queryCacheID))!==null)
		{
			$this->getConnection()->queryCachingCount--;
			$cacheKey='yii:dbquery'.$this->getConnection()->connectionString.':'.$this->getConnection()->username;
			$cacheKey.=':'.$this->getText().':'.serialize(array_merge($this->_paramLog,$params));
			if(($result=$cache->get($cacheKey))!==false)
			{
				Yii::trace('Query result found in cache','system.db.CDbCommand');
				return $result;
			}
		}

		try
		{
			if($this->getConnection()->enableProfiling)
				Yii::beginProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');

			$this->prepare();
			if($params===array())
				$this->getPdoStatement()->execute();
			else
				$this->getPdoStatement()->execute($params);

			if($method==='')
				$result=new DbDataReader($this);
			else
			{
				$mode=(array)$mode;
				$result=call_user_func_array(array($this->getPdoStatement(), $method), $mode);
				$this->getPdoStatement()->closeCursor();
			}

			if($this->getConnection()->enableProfiling)
				Yii::endProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');

			if(isset($cache,$cacheKey))
				$cache->set($cacheKey, $result, $this->getConnection()->queryCachingDuration, $this->getConnection()->queryCachingDependency);

			return $result;
		}
		catch(Exception $e)
		{
			if($this->getConnection()->enableProfiling)
				Yii::endProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');
            $errorInfo = $e instanceof PDOException ? $e->errorInfo : null;
            $message = $e->getMessage();
			Yii::log(Yii::t('yii','CDbCommand::{method}() failed: {error}. The SQL statement executed was: {sql}.',
				array('{method}'=>$method, '{error}'=>$message, '{sql}'=>$this->getText().$par)),CLogger::LEVEL_ERROR,'system.db.CDbCommand');
            if(YII_DEBUG)
            	$message .= '. The SQL statement executed was: '.$this->getText().$par;
			throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}',
				array('{error}'=>$message)),(int)$e->getCode(),$errorInfo);
		}
	}
}
